package org.budo.dubbo.protocol.http.exporter;

import org.budo.dubbo.protocol.http.Consts;
import org.budo.dubbo.protocol.http.exception.BudoRuntimeException;
import org.budo.dubbo.protocol.http.exporter.util.ExportUtil;
import org.budo.support.lang.util.ArrayUtil;
import org.budo.support.spring.io.util.ResourceUtil;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.Resource;

import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.config.ServiceConfig;

import lombok.Getter;
import lombok.Setter;

/**
 * 以 budo-http 协议暴露 dubbo 服务的工具
 * 
 * @author lmw
 */
@Getter
@Setter
public class BudoDubboHttpExporter implements ApplicationContextAware, InitializingBean {
    private static final Logger log = LoggerFactory.getLogger(BudoDubboHttpExporter.class);

    /**
     * 添加了Sign，替换了Exception
     */
    private String filter = "budo-exception,provider-side-sign,-exception";

    /**
     * 默认开启参数验证
     */
    private String validation = "false";

    private Class<?>[] interfaceTypes = new Class<?>[0];

    private ApplicationContext applicationContext;

    private Resource[] interfaceTypeResources;

    /**
     * 服务端解析请求时候，如果客户端没有指定序列化方式，则用服务端配置的默认方式
     */
    private String serialization = Consts.SerializationDefault; // http调用默认使用json序列化

    /**
     * 暴露服务
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        try {
            Class<?>[] interfaceTypesFromResource = ResourceUtil._readLineToTypes(this.getInterfaceTypeResources());
            Class<?>[] allInterfaceTypes = ArrayUtil.concat(this.getInterfaceTypes(), interfaceTypesFromResource);

            if (null == allInterfaceTypes || allInterfaceTypes.length < 1) {
                log.error("#67 interfaceTypes is null or empty, this.getInterfaceTypes()=" + this.getInterfaceTypes() + ", interfaceTypesFromResource=" + interfaceTypesFromResource);
                return;
            }

            for (Class<?> interfaceType : allInterfaceTypes) {
                this.exportService(interfaceType);
            }
        } catch (Throwable e) {
            log.error("#55 BudoDubboHttpExporter.exportDubboServices error, e=" + e, e);
            throw new BudoRuntimeException("#56 exportDubboServices error, e=" + e, e);
        }
    }

    private void exportService(Class<?> interfaceType) {
        Object beanRef = applicationContext.getBean(interfaceType);

        ServiceConfig<Object> serviceConfig = ExportUtil.newServiceConfig(interfaceType, beanRef);
        serviceConfig.setValidation(this.getValidation());
        serviceConfig.setFilter(this.getFilter());

        serviceConfig.export();

        log.info("#85 exported, interfaceType=" + interfaceType + ", beanRef=" + beanRef.getClass() + "@" + beanRef.hashCode());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}